#include "game.hpp"
#include "main.hpp"
#include "eq.hpp"
#include "map.hpp"
#include "hero.hpp"
#include "GUI.hpp"
#include "minigame.hpp"
#include <ctime>
#include <cstdlib>
#include <allegro.h>
#include <fstream>
#include <vector>
#include <cstdlib>
#include <iostream>


/*short _KEY[] = {0x0D, 0x20, 0x08, //ENTER, SPACE, BACKSPACE
               0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, //0, 1, 2, 3, 4, 5, 6, 7, 8, 9
               0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, //A, B, C, D, E, F, G, H, I, J
               0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, //K, L, M, N, O, P, Q, R, S, T
               0x55, 0x56, 0x57, 0x58, 0x59, 0x5A}; // U, V, W, X, Y, Z*/


cGame::cGame(int w, int h)
{
    //przypisujemy wartosci szerokosci i wysokosci ekranu
    size = new sPoint(w, h);

    //inicjujemy ziarno generatora liczb pseudolosowych
    srand(time(NULL));

    //inicjujemy biblioteke allegro
    allegroInit();

    //tworzymy bufor
    bufor = create_bitmap(size->x, size->y);

    //tworzenie mini gry
    minigame = new cMiniGame(size->x, size->y);//(size->x,size->y);

    //wlaczamy gre
    run = true;

    //odpauzowujemy gre
    pause = false;

    //ladujemy info o itemach
    itemInfo = new cItemResources;
    loadItems();

    //ladujemy info o moobkach
    loadMoobs();

    //tworzymy bohatera
    hero = new cHero(200, 100, itemInfo);

    //tworzymy i ladujemy mape
    map = new cMap(itemInfo);
    //map->generate();
    map->load("Data\\map1.map");

    //tworzymy minimape
    minimap = new cMiniMap(map->size->x, map->size->y, 0, 0, map);

    if (map->fogOn) hero->actualiseFog(map);

    //tworzymy nowy punkt show
    show = new sPoint(0, 0);
    show = countShow();

    //myszka jest domyslnie spuszczona
    MOUSE_FREE = true;

    //zerujemy wartosci dla liczenia FPS
    last_time_FPS = time(NULL);
    frames = FPS = 0;
    lastUpdate = clock();
    dt = accumulator = 0.0f;
    TIME_STEP = 30.0f;
    MAX_ACCUMULATED_TIME = 1000.0f;

    log = new cLogger;


    //włączamy kodowanie w konsoli na UTF-8
    //system("chcp 65001");
}

cGame::~cGame()
{
    destroy_bitmap(bufor);//niszczymy bufor
    delete map;//kasujemy mape
    delete hero;//kasujemy bohatera
    delete size;//kasujemy obiekt size
    delete show;//kasujemy obiekt show
    delete itemInfo;//kasujemy info o itemkach
    for (int i = 0; i < NPC.size(); i++)
        delete NPC[i];
    allegro_exit();//wychodzimy z allegro
}

void cGame::timeActualisation()
{
    dt = clock() - lastUpdate; //obliczenie czasu od ostatniej klatki
    lastUpdate += dt; //podmiana
    dt = (dt > 0 ? dt : 0); //upewniamy sie, ze dt >= 0
    accumulator += dt;
    accumulator = (MAX_ACCUMULATED_TIME < (accumulator > 0 ? accumulator : 0) ? MAX_ACCUMULATED_TIME : (accumulator > 0 ? accumulator : 0));
}

sPoint * cGame::countShow()
{
    //nowy punkt s
    sPoint * s = new sPoint(0, 0);
    //zmienna do wyswietlania mapy na srodku
    bool middleX = false, middleY = false;

    if (map->size->x * TILE_SIZE < bufor->w) {s->x = 0; middleX = true;}
    if (map->size->y * TILE_SIZE < bufor->h) {s->y = 0; middleY = true;}

    //obliczamy na podstawie pozycji bohatera
    if (!middleX) s->x = hero->pos->x - bufor->w / 2;
    if (!middleY) s->y = hero->pos->y - bufor->h / 2;

    //sytualcje gdy wyswietlanie mapy jest liczone inaczej
    if (!middleX) if (hero->pos->x < bufor->w / 2) s->x = 0;//jesli bohater jest przy boku mapy
    if (!middleY) if (hero->pos->y < bufor->h / 2) s->y = 0;//jesli bohater jest przy boku mapy
    if (!middleX) if (hero->pos->x > map->size->x * TILE_SIZE - bufor->w / 2) s->x = map->size->x * TILE_SIZE - bufor->w;//jesli bohater jest przy boku mapy
    if (!middleY) if (hero->pos->y > map->size->y * TILE_SIZE - bufor->h / 2) s->y = map->size->y * TILE_SIZE - bufor->h;//jesli bohater jest przy boku mapy

    return s;
}

bool cGame::allegroInit()
{
    //inicjalizacja bilbioteki allegro
    allegro_init();

    //wlaczenie obslugi klawiatury
    install_keyboard();

    //wlaczenie obslugi timerow
    install_timer();

    //ustawienie glebi kolorow
    set_color_depth(32);

    //ustawienie trybu graficznego gry
    if (!set_gfx_mode(GFX_AUTODETECT_WINDOWED, size->x, size->y, 0, 0)) return false;

    //wlaczenie obslugi myszki
    installMouse();
    return true;
}

bool cGame::isRunning()
{
    return run;//zwraca czy gra jest wlaczona
}

void cGame::draw()
{
    //obliczmay punkt show
    delete show;
    show = countShow();

    //czyscimy bitmape
    clear_to_color(bufor, 0x000000);

    //rysujemy mape
    map->draw(bufor, show);

    //rysujemy NPC
    for (int i = 0; i < NPC.size(); i++)
    {
        NPC[i]->draw(bufor, show, map->shift, map->fogOfWar, map->fogOn);
    }

    //rysujemy mooby
    for (int i = 0; i < moobs.size(); i++)
    {
        moobs[i]->draw(bufor, show, map->shift, map->fogOfWar, map->fogOn);
    }

    //rysujemy bohatera
    hero->draw(bufor, show, map->shift);

    //rysujemy minimape
    if (minimap->isDrawing)
        minimap->draw(bufor, hero->pos->x, hero->pos->y, map->size->x * TILE_SIZE, map->size->y * TILE_SIZE);

    //rysujemy logger
    log->draw(bufor);

    //zwiekszamy liczbe klatek
    frames++;
    int tm = time(NULL);
    if (tm - last_time_FPS > 0)
    {
        FPS = frames;
        frames = 0;
        last_time_FPS = tm;
    }

    textprintf_ex(bufor, font, 0, 10, 0xFFFFFF, -1, "FPS: %d", FPS);

    //wyswietlamy bufor na ekranie
    masked_blit(bufor, screen, 0, 0, 0, 0, size->x, size->y);
}


void cGame::main_menu()
{
    //glowne menu, tego nie bede tlumaczyl, bo to zwykle stworzenie kontrolek GUI i ich obsługa ;]
    GUI = new cGUI(0, 0, size->x, size->y);
    int button_01 = GUI->ctrlAdd(BUTTON_TYPE, size->x/2 - 150, 48, 300, 90, "Start");
    int button_02 = GUI->ctrlAdd(BUTTON_TYPE, size->x/2 - 150, 90 + 96, 300, 90, "Options");
    int button_03 = GUI->ctrlAdd(BUTTON_TYPE, size->x/2 - 150, 180 + 144, 300, 90, "Credits");
    int button_04 = GUI->ctrlAdd(BUTTON_TYPE, size->x/2 - 150, 270 + 192, 300, 90, "Exit");

    int input_01 = GUI->ctrlAdd(INPUT_TYPE, 10, 10, 100, 20, "Pawel Chwala", 0);

    while (!key[KEY_ESC])
    {
        if (GUI->isClicked(button_01)) {start_menu(); break;}
        if (GUI->isClicked(button_02)) {options_menu(); break;}
        if (GUI->isClicked(button_03)) {credits_menu(); break;}
        if (GUI->isClicked(button_04)) {exit_game(); break;}

        GUI->draw();
        rest(30);
    }

    delete GUI;
}

void cGame::start_menu()
{

}

void cGame::options_menu()
{

}

void cGame::credits_menu()
{

}

void cGame::exit_game()
{

}

//ladujemy ifnormacje o itemach
void cGame::loadItems()
{
    //otwieramy plik z info o itemkach
    std::fstream file;
    file.open("Data\\items.dat", std::ios::in);

    if (!file) return;//jesli plik jest zle otwarty (nie istnieje) koneic dzialania funkcji

    cItemInfo item;//tworzymy obiekt tymczasowy z info o itemku

    //wczytujemy do niego te informacje
    while (!file.eof())
    {
        file >> item.name;
        if (item.name[0] == '/') break;//komentarz koncowy
        repairName(item.name);//naprawiamy naze itemka
        file >> item.buy;
        file >> item.sell;
        file >> item.dmg[0];
        file >> item.dmg[1];
        file >> item.def;
        file >> item.stack;

        //dodajemy do kolejki
        itemInfo->item.push_back(item);
    }

    //zamykamy plik
    file.close();
}

void cGame::loadMoobs()
{
    std::fstream file;
    std::string t;
    cMoobResources * m;

    file.open("Data\\moobs.dat", std::ios::in);
    if (!file) return;

    while (!file.eof())
    {
        m = new cMoobResources;
        file >> m->name;
        t = "GFX\\Moobs\\";
        t += m->name.c_str();
        t += ".bmp";
        m->img = load_bmp(t.c_str(), default_palette);
        if (!m->img) {delete m; continue;}
        repairName(m->name);
        file >> m->dmg;
        file >> m->def;
        file >> m->hp;
        file >> m->mp;
        moobInfo.push_back(m);
    }
}

void cGame::installMouse()
{
    install_mouse();
    show_mouse(screen);
    unscare_mouse();
}

void cGame::checkKeys()
{
    //jesli nacisniemy E to wlaczamy rysowanie EQ
    if (key[KEY_E] && !keys[KEY_E])
    {
        keys[KEY_E] = true;

        hero->eq->isDrawing = !hero->eq->isDrawing;
        pause = !pause;
    }
    else if (!key[KEY_E]) keys[KEY_E] = false;

    if (key[KEY_M] && !keys[KEY_M])
    {
        keys[KEY_M] = true;

        minimap->isDrawing = !minimap->isDrawing;
    }
    else if (!key[KEY_M]) keys[KEY_M] = false;

    ///KOLEJNE KLAWISZE TUTAJ WPISUJEMY
}

void cGame::addNPC(float x, float y, float angle, const char * filename)
{
    cNPC * npc = new cNPC(x, y, angle, filename, itemInfo);
    NPC.push_back(npc);
}

void cGame::addMoob(int id, float x, float y, short type, float angle)
{
    cMoob * moob = new cMoob(id, x, y, type, moobInfo[id], angle);
    moobs.push_back(moob);
}
